package com.jingdianjichi.auth.application.context;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 登录上下文对象,这里就是有ThreadLocal的
 */
public class LoginContextHolder {

    //上下文对象亲
    //private static final ThreadLocal<Map<String,Object>> THREAD_LOCAL=new ThreadLocal<>();   //我们放map,因为我们想放很多的东西去传递亲

    //我们用这个
    private static final InheritableThreadLocal<Map<String,Object>> THREAD_LOCAL=new InheritableThreadLocal<>();

    /*
        区别:
            ThreadLocal在上下文切换的时候有问题的亲

        当某个线程（父线程）创建子线程时，如果使用 ThreadLocal，那么子线程将无法获得父线程中存储的 ThreadLocal 变量的值，因为这两者完全独立，彼此之间没有关联。
            但如果使用 InheritableThreadLocal，父线程中的数据会在子线程创建时被复制到子线程中，这就解决了需要在线程间传递上下文数据的问题。
     */

    //
    //private static final TransmitThreadLocal

    /*
        但是InheritableThreadLocal也有自己的问题
            /线程池复用的时候,就是多线程复用的时候发现也有问题,所以阿里NB出现了TransmitThreadLocal
                /他就解决了这个问题,而且更加的灵活NB
     */

    /**
     * 放值,亲
     */
    public static void set(String key,Object val){
        Map<String, Object> map = getThreadLocalMap();

        map.put(key,val);
    }

    /**
     * 先解决,放到ThreadLocal中, 在解决如果有值的话,我们不能去覆盖他,复用他
     */
    public static Map<String,Object> getThreadLocalMap(){
        Map<String, Object> map = THREAD_LOCAL.get();   //这个就是当前线程已经存在的值亲

        //不是空的直接返回,这里一定是并发的亲
        if (Objects.isNull(map)){
            //初始化,但是为了线程安全我们初始化
            map=new ConcurrentHashMap<>();
            /*
                ConcurrentHashMap 是线程安全的，可以在多线程环境中安全地使用。它为读操作和写操作提供了高效的并发支持。
                HashMap 是非线程安全的，也就是说，当多个线程同时对 HashMap 进行读写操作时，可能会导致数据的不一致或者出现 ConcurrentModificationException。
             */
            THREAD_LOCAL.set(map);
        }

        return map;
    }

    /**
     * 取值
     */
    public static Object get(String key){
        Map<String, Object> map = getThreadLocalMap();

        Object o = map.get(key);

        return o;
    }

    /**
     * 清除上下文亲
     */
    public static void remove(){
        THREAD_LOCAL.remove();
    }

    /**
     * 获得loginId
     */
    public static String getLoginId(){
        return (String) getThreadLocalMap().get("loginId");
    }
}
